//
//  ModelController.m
//  HWFinal
//
//  Created by student on 2021/12/2.
//  Copyright © 2021 demo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ModelController.h"

@interface ModelController ()<NSURLSessionDelegate>

@property(strong, nonatomic) NSString* host;
@property(strong, nonatomic) AFHTTPSessionManager* manager;
@property(strong, nonatomic) NSFileManager* fileManager;
@property(strong, nonatomic) NSString* cacheDir;

@end

@implementation ModelController

//单例模式
static ModelController* _instance;

+(ModelController*)getInstance
{
    if(_instance == nil){
        _instance = [[self alloc]initWithHost: @"http://42.194.159.223:3000/"];// The host to be modified!
    }
    return _instance;
}

-(ModelController*)initWithHost: (NSString*)host
{
    self = [super init];
    
    self.host = host;
    self.manager = [AFHTTPSessionManager manager];
    self.manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.manager.requestSerializer = [AFJSONRequestSerializer serializer];
    self.manager.responseSerializer = [AFJSONResponseSerializer serializer];
    
    self.fileManager = [NSFileManager defaultManager];
    self.cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    
    self.cur_user = nil;
    
    [self deleteCache];
    
    return self;
}

-(NSString*) getCurrentTimeStamp
{
    NSDate* date = [NSDate date];
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc]init];
    [dateFormatter setDateFormat: @"yyyy-MM-dd HH:mm:ss"];
    NSString* dateStr = [dateFormatter stringFromDate:date];
    return dateStr;
}

-(NSNumber*) getType: (NSString*)url
{
    NSArray* arr = [url componentsSeparatedByString:@"."];
    NSString* extname = arr[arr.count - 1];
    extname = extname.lowercaseString;
    if([extname isEqualToString:@"png"] || [extname isEqualToString:@"jpeg"] || [extname isEqualToString:@"jpg"] || [extname isEqualToString:@"gif"]){
        return [NSNumber numberWithInt:0];
    }
    else if([extname isEqualToString:@"mov"] || [extname isEqualToString:@"mp4"]){
        return [NSNumber numberWithInt:1];
    }
    else{
        return [NSNumber numberWithInt:0];
    }
}

-(NSDictionary*) getRequestWithDirectory: (NSDictionary*)jsonDic
                                  andURL: (NSString*)subURLString
{
    NSString* urlString = [self.host stringByAppendingString:subURLString];
    NSError* error;
    NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDic options:NSJSONWritingPrettyPrinted error:&error];
    NSString* jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSLog(@"\n==========GET==========\n%@", urlString);
    NSLog(@"\n-------Request-------\n%@\n---------------------", jsonString);
    
    __block NSDictionary* retDic;
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    
    [self.manager GET:urlString
           parameters:jsonDic
              headers:nil
             progress:nil
              success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                  
                  retDic = [responseObject objectForKey:@"data"];
                  NSData* jsonData = [NSJSONSerialization dataWithJSONObject:retDic options:NSJSONWritingPrettyPrinted error:nil];
                  NSString* jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
                  NSLog(@"\n-------Response-------\n%@\n---------------------", jsonString);
                  NSLog(@"\n===========Success===========");
                  dispatch_semaphore_signal(sem);
              }
              failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                  
                  NSLog(@"\n===========Failed===========\n[Error]Bad request! Could not connect to the server");
                  retDic = nil;
                  dispatch_semaphore_signal(sem);
              }];
    
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    return retDic;
}

-(NSDictionary*) postRequestWithDirectory: (NSDictionary*)jsonDic
                                   andURL: (NSString*)subURLString
{
    NSString* urlString = [self.host stringByAppendingString:subURLString];
    NSError* error;
    NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDic options:NSJSONWritingPrettyPrinted error:&error];
    NSString* jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSLog(@"\n==========POST==========\n%@", urlString);
    NSLog(@"\n-------Request-------\n%@\n---------------------", jsonString);
    
    __block NSDictionary* retDic = nil;
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    
    [self.manager POST:urlString
            parameters:jsonDic
               headers:nil
              progress:nil
               success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                   
                   retDic = [responseObject objectForKey:@"data"];
                   NSData* jsonData = [NSJSONSerialization dataWithJSONObject:retDic options:NSJSONWritingPrettyPrinted error:nil];
                   NSString* jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
                   NSLog(@"\n-------Response-------\n%@\n---------------------", jsonString);
                   NSLog(@"\n===========Success===========");
                   dispatch_semaphore_signal(sem);
               }
               failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                   
                   NSLog(@"\n===========Failed===========\n[Error]Bad request! Could not connect to the server");
                   retDic = nil;
                   dispatch_semaphore_signal(sem);
               }];
    
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    return retDic;
}

-(NSDictionary*) postRequestWithDirectory: (NSDictionary*)jsonDic
                                   andURL: (NSString*)subURLString
                              andFileData: (NSMutableArray*)fileDatas
                                  andName: (NSString*) name
                             andFileNames: (NSMutableArray*) filenames
{
    NSString* urlString = [self.host stringByAppendingString:subURLString];
    NSError* error;
    NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDic options:NSJSONWritingPrettyPrinted error:&error];
    NSString* jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSLog(@"\n==========POST==========\n%@", urlString);
    NSLog(@"\n-------Request-------\n%@\n---------------------", jsonString);
    
    __block NSDictionary* retDic = [[NSDictionary alloc]initWithObjectsAndKeys: [NSNumber numberWithBool:true], @"res", nil];
    
    [self.manager POST:urlString
            parameters:jsonDic
               headers:nil
constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
    for(int i = 0; i < fileDatas.count; i++){
        [formData appendPartWithFileData:fileDatas[i]
                                    name:name
                                fileName:filenames[i]
                                mimeType:@"multipart/form-data"];
        NSLog(@"\n-----Upload:%@-----", filenames[i]);
    }
}
              progress:nil
               success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                   NSLog(@"\n===========Success===========");
               }
               failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                   
                   NSLog(@"\n===========Failed===========\n[Error]Bad request! Could not connect to the server");
                   retDic = nil;
               }];
    
    return retDic;
}

//Input: User
//Output: -1 = bad request, 0 = success, 1 = fail
-(int) regist: (NSString*) u_id
  andPassword: (NSString*) password
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            u_id, @"u_id",
                            password, @"password",
                            nil];
    NSDictionary* resDic = [self postRequestWithDirectory:reqDic andURL:@"regist"];
    
    if(resDic == nil){
        return -1;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        return 0;
    }
    else{
        return 1;
    }
}

//Input: id and password
//Output: -1 = bad request, 0 = success, 1 = undefined id, 2 = wrong password
-(int) signIn: (NSString*) u_id
  andPassword: (NSString*) password
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            u_id, @"u_id",
                            password, @"password",
                            nil];
    NSDictionary* resDic = [self postRequestWithDirectory:reqDic andURL:@"signup"];
    
    if(resDic == nil){
        return -1;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        NSURL* head_url = [NSURL URLWithString:[resDic objectForKey:@"head_image"]];
        UIImage* head = [UIImage imageWithData:[NSData dataWithContentsOfURL:head_url]];
        self.cur_user = [[User alloc]initWithID:[resDic objectForKey:@"u_id"]
                                        andName:[resDic objectForKey:@"name"]
                                    andPassword:[resDic objectForKey:@"password"]
                                        andHead:head
                                       andEmail:[resDic objectForKey:@"email"]
                                       andphone:[resDic objectForKey:@"phone"]
                                       andHobby:[resDic objectForKey:@"hobby"]
                                     andContent:[resDic objectForKey:@"content"]];
        return 0;
    }
    else{
        int ret = [[resDic objectForKey:@"err"] intValue];
        return ret;
    }
}

//Usually return 0
-(int) signOut{
    self.cur_user = nil;
    return 0;
}

//Input: user id
//Output: Raw User, nil means undefined user or bad request.
-(RawUser*) getRawUser: (NSString*) u_id
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            u_id, @"u_id",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"get_rawuser"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        NSURL* head_url = [NSURL URLWithString:[resDic objectForKey:@"head_image"]];
        UIImage* head = [UIImage imageWithData:[NSData dataWithContentsOfURL:head_url]];
        RawUser* ru = [[RawUser alloc]initWithUID:u_id
                                          andName:[resDic objectForKey:@"name"]
                                          andHead: head];
        return ru;
    }
    else{
        return nil;
    }
}

//Input: user id
//Output: User(without password), nil means undefined user or bad request.
-(User*) getUser: (NSString*) u_id
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            u_id, @"u_id",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"get_user"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        NSURL* head_url = [NSURL URLWithString:[resDic objectForKey:@"head_image"]];
        UIImage* head = [UIImage imageWithData:[NSData dataWithContentsOfURL:head_url]];
        User* user = [[User alloc]initWithID:u_id
                                     andName:[resDic objectForKey:@"name"]
                                     andHead:head
                                    andEmail:[resDic objectForKey:@"email"]
                                    andphone:[resDic objectForKey:@"phone"]
                                    andHobby:[resDic objectForKey:@"hobby"]
                                  andContent:[resDic objectForKey:@"content"]];
        return user;
    }
    else{
        return nil;
    }
}

//Input: User
//Output: -1 = bad request, 0 = success, 1 = fail
-(int) modifyUser: (User*) user
{
    NSData* fileData = UIImagePNGRepresentation(user.head_img);
    NSMutableArray* fileDataArr = [[NSMutableArray alloc]initWithObjects:fileData, nil];
    NSMutableArray* fileNameArr = [[NSMutableArray alloc]initWithObjects:@"test.png", nil];
    
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            user.u_id, @"u_id",
                            user.name, @"name",
                            user.password, @"password",
                            user.email, @"email",
                            user.phone, @"phone",
                            user.hobby, @"hobby",
                            user.content, @"content",
                            nil];
    NSDictionary* resDic = [self postRequestWithDirectory:reqDic andURL:@"modify_user" andFileData:fileDataArr andName:@"avatar" andFileNames:fileNameArr];
    
    if(reqDic == nil){
        return -1;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        return 0;
    }
    else{
        return 1;
    }
}

//Input: Components of articles, images should be url string, the two arrays must be equal length.
//Output: -1 = bad request, 0 = success, 1 = fail
-(int) postArticle: (int) field
        andContent: (NSString*) content
         andImages: (NSMutableArray*) images
{
    NSMutableArray* fileDataArr = [[NSMutableArray alloc]init];
    NSMutableArray* fileNameArr = [[NSMutableArray alloc]init];
    for(int i = 0; i < images.count; i++){
        NSData* fileData = [NSData dataWithContentsOfFile: images[i] options:NSDataReadingUncached error:nil];
        [fileDataArr addObject:fileData];
        NSArray* arr = [images[i] componentsSeparatedByString:@"/"];
        NSString* name = arr[arr.count - 1];
        [fileNameArr addObject:name];
    }
    NSString* time_stamp = [self getCurrentTimeStamp];
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            self.cur_user.u_id, @"u_id",
                            [NSNumber numberWithInt:field], @"type",
                            content, @"content",
                            time_stamp, @"time_stamp",
                            nil];
    //Question With FileData Arr
    NSDictionary* resDic = [self postRequestWithDirectory:reqDic andURL:@"post_article" andFileData:fileDataArr andName:@"medias" andFileNames:fileNameArr];
    
    if(reqDic == nil){
        return -1;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        return 0;
    }
    else{
        return 1;
    }
}

//Input: The conditions of the articles
//Output: A single article with images in url.
-(NSMutableArray*) getArticleWithType: (int) type
                              andMode: (NSString*) mode;
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            [NSNumber numberWithInt:type], @"type",
                            mode, @"mode",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"get_article"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    NSMutableArray* retArticles = [[NSMutableArray alloc]init];
    if(res){
        NSMutableArray* arr = [resDic objectForKey:@"articles"];
        
        for(int i = 0; i < arr.count; i++){
            NSDictionary* dic = arr[i];
            
            NSMutableArray* images = [[NSMutableArray alloc]init];
            NSMutableArray* types = [[NSMutableArray alloc]init];
            NSMutableArray* recs = [dic objectForKey:@"medias"];
            
            for(int j = 0; j < recs.count; j++){
                NSString* url = recs[j];
                [images addObject:url];
                NSNumber* type = [self getType:url];
                [types addObject: type];
            }
            
            Article* article = [[Article alloc]initWithUID: [dic objectForKey:@"u_id"]
                                                    andAID: [dic objectForKey:@"a_id"]
                                                  andField: [[dic objectForKey:@"type"] intValue]
                                                andContent: [dic objectForKey:@"content"]
                                                 andImages: images
                                                  andTypes: types
                                              andTimeStamp:[dic objectForKey:@"time_stamp"]];
            [retArticles addObject:article];
        }
    }
    return retArticles;
}

//Input: article id
//Output: A single comment
-(NSMutableArray*) getCommentWithAID: (NSString*) a_id
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            a_id, @"a_id",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"get_comment"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    NSMutableArray* retComments = [[NSMutableArray alloc]init];
    if(res){
        NSMutableArray* arr = [resDic objectForKey:@"comments"];
        
        
        for(int i = 0; i < arr.count; i++){
            NSDictionary* dic = arr[i];
            
            Comment* comment = [[Comment alloc]initWithUID:[dic objectForKey:@"u_id"]
                                                    andAID:a_id
                                                andContent:[dic objectForKey:@"comment"]
                                              andTimeStamp:[dic objectForKey:@"time_stamp"]];
            
            [retComments addObject:comment];
        }
    }
    return retComments;
}

//Input: article id
//Output: the num of support, if negative, couldnot support again
-(int) getSupportWithAID: (NSString*) a_id
{
    NSString* u_id;
    if(self.cur_user == nil){
        u_id = @"";
    }
    else{
        u_id = self.cur_user.u_id;
    }
    
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            a_id, @"a_id",
                            u_id, @"u_id",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"get_support"];
    
    if(resDic == nil){
        return -1;
    }
    int ret = [[resDic objectForKey:@"num_support"] intValue];
    BOOL isSupported = [[resDic objectForKey:@"is_supported"] boolValue];
    if(isSupported){
        ret = -ret;
    }
    
    return ret;
}

//Input: article id
//Output: -1 = bad request, 0 = success, 1 = fail
-(int) support: (NSString*) a_id
{
    NSString* time_stamp = [self getCurrentTimeStamp];
    
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            a_id, @"a_id",
                            self.cur_user.u_id, @"u_id",
                            time_stamp, @"time_stamp",
                            nil];
    NSDictionary* resDic = [self postRequestWithDirectory:reqDic andURL:@"support"];
    if(resDic == nil){
        return -1;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        return 0;
    }
    else{
        return 1;
    }
}

//Input: article id and content
//Output: -1 = bad request, 0 = success, 1 = fail
-(int) comment: (NSString*) a_id
          with: (NSString*) content
{
    NSString* time_stamp = [self getCurrentTimeStamp];
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            a_id, @"a_id",
                            self.cur_user.u_id, @"u_id",
                            content, @"comment",
                            time_stamp, @"time_stamp",
                            nil];
    NSDictionary* resDic = [self postRequestWithDirectory:reqDic andURL:@"comment"];
    
    if(resDic == nil){
        return -1;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        return 0;
    }
    else{
        return 1;
    }
}

//Input: the query string
//Output: All articles that satisfy(the array can be allocated but the count is 0), nil means bad request.
-(NSMutableArray*) queryArticle: (NSString*) str
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            str, @"str",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"query"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    NSMutableArray* retArticles = [[NSMutableArray alloc]init];
    if(res){
        NSMutableArray* arr = [resDic objectForKey:@"articles"];
        
        for(int i = 0; i < arr.count; i++){
            NSDictionary* dic = arr[i];
            
            NSMutableArray* images = [[NSMutableArray alloc]init];
            NSMutableArray* types = [[NSMutableArray alloc]init];
            NSMutableArray* recs = [dic objectForKey:@"medias"];
            
            for(int j = 0; j < recs.count; j++){
                NSString* url = recs[j];
                [images addObject:url];
                NSNumber* type = [self getType:url];
                [types addObject: type];
            }
            
            Article* article = [[Article alloc]initWithUID: [dic objectForKey:@"u_id"]
                                                    andAID: [dic objectForKey:@"a_id"]
                                                  andField: [[dic objectForKey:@"type"] intValue]
                                                andContent: [dic objectForKey:@"content"]
                                                 andImages: images
                                                  andTypes: types
                                              andTimeStamp:[dic objectForKey:@"time_stamp"]];
            [retArticles addObject:article];
        }
    }
    return retArticles;
}

//Input: cur_num
//Output: A single article with images in url.
-(NSMutableArray*) getMyArticle
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            self.cur_user.u_id, @"u_id",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"my_article"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    NSMutableArray* retArticles = [[NSMutableArray alloc]init];
    if(res){
        NSMutableArray* arr = [resDic objectForKey:@"articles"];
        
        for(int i = 0; i < arr.count; i++){
            NSDictionary* dic = arr[i];
            
            NSMutableArray* images = [[NSMutableArray alloc]init];
            NSMutableArray* types = [[NSMutableArray alloc]init];
            NSMutableArray* recs = [dic objectForKey:@"medias"];
            
            for(int j = 0; j < recs.count; j++){
                NSString* url = recs[j];
                [images addObject:url];
                NSNumber* type = [self getType:url];
                [types addObject: type];
            }
            
            Article* article = [[Article alloc]initWithUID: [dic objectForKey:@"u_id"]
                                                    andAID: [dic objectForKey:@"a_id"]
                                                  andField: [[dic objectForKey:@"type"] intValue]
                                                andContent: [dic objectForKey:@"content"]
                                                 andImages: images
                                                  andTypes: types
                                              andTimeStamp:[dic objectForKey:@"time_stamp"]];
            [retArticles addObject:article];
        }
    }
    return retArticles;
}

//Input: cur_num
//Output: A single support with raw content.
-(NSMutableArray*) getMySupport
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            self.cur_user.u_id, @"u_id",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"my_support"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    NSMutableArray* retSupports = [[NSMutableArray alloc]init];
    if(res){
        NSMutableArray* arr = [resDic objectForKey:@"supports"];
        
        for(int i = 0; i < arr.count; i++){
            NSDictionary* dic = arr[i];
            
            Support* support = [[Support alloc]initWithUID:[dic objectForKey:@"u_id"]
                                                    andAID:[dic objectForKey:@"a_id"]
                                                    andRaw:[dic objectForKey:@"raw_content"]
                                              andTimeStamp:[dic objectForKey:@"time_stamp"]];
            
            [retSupports addObject:support];
        }
    }
    return retSupports;
}

//Input: cur_num
//Output: A single comment with raw content.
-(NSMutableArray*) getMyComment
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            self.cur_user.u_id, @"u_id",
                            nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"my_comment"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    NSMutableArray* retComments = [[NSMutableArray alloc]init];
    if(res){
        NSMutableArray* arr = [resDic objectForKey:@"comments"];
        
        for(int i = 0; i < arr.count; i++){
            NSDictionary* dic = arr[i];
            
            Comment* comment = [[Comment alloc]initWithUID:[dic objectForKey:@"u_id"]
                                                    andAID:[dic objectForKey:@"a_id"]
                                                    andRaw:[dic objectForKey:@"raw_content"]
                                                andContent:[dic objectForKey:@"content"]
                                              andTimeStamp:[dic objectForKey:@"time_stamp"]];
            
            [retComments addObject:comment];
        }
    }
    return retComments;
}

//Input: a_id: NSString
//Output: An article with a_id.
-(Article*) getArticleWithAID: (NSString*) a_id
{
    NSDictionary* reqDic = [[NSDictionary alloc]initWithObjectsAndKeys:
                            a_id, @"a_id", nil];
    NSDictionary* resDic = [self getRequestWithDirectory:reqDic andURL:@"get_spec_article"];
    
    if(resDic == nil){
        return nil;
    }
    BOOL res = [[resDic objectForKey:@"res"] boolValue];
    if(res){
        resDic = [resDic objectForKey:@"article"];
        NSMutableArray* images = [[NSMutableArray alloc]init];
        NSMutableArray* types = [[NSMutableArray alloc]init];
        NSMutableArray* recs = [resDic objectForKey:@"medias"];
        
        for(int j = 0; j < recs.count; j++){
            NSString* url = recs[j];
            [images addObject:url];
            NSNumber* type = [self getType:url];
            [types addObject: type];
        }
        
        Article* article = [[Article alloc]initWithUID: [resDic objectForKey:@"u_id"]
                                                andAID: [resDic objectForKey:@"a_id"]
                                              andField: [[resDic objectForKey:@"type"] intValue]
                                            andContent: [resDic objectForKey:@"content"]
                                             andImages: images
                                              andTypes: types
                                          andTimeStamp:[resDic objectForKey:@"time_stamp"]];
        return article;
    }
    else{
        return nil;
    }
}

-(BOOL) downloadFileToCache: (NSString*) url
{
    __block BOOL ret = false;
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    
    AFURLSessionManager* urlManager = [[AFURLSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    
    NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    NSArray* arr = [url componentsSeparatedByString:@"/"];
    NSString* name = arr[arr.count - 1];
    NSString* filePath = [[NSString alloc]initWithFormat:@"%@/%@", self.cacheDir, name];
    
    NSURLSessionDownloadTask* task = [urlManager downloadTaskWithRequest:request progress: nil destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        
        return [NSURL fileURLWithPath:filePath];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        
        ret = true;
        dispatch_semaphore_signal(sem);
    }];
    
    [task resume];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    
    return ret;
}

-(UIImage*) loadImageFromCache: (NSString*) url
{
    NSArray* arr = [url componentsSeparatedByString:@"/"];
    NSString* name = arr[arr.count - 1];
    NSString* filePath = [[NSString alloc]initWithFormat:@"%@/%@", self.cacheDir, name];
    BOOL ret = [self.fileManager fileExistsAtPath:filePath];
    if(!ret){
        return nil;
    }
    
    UIImage* img = [UIImage imageWithContentsOfFile: filePath];
    return img;
}

-(NSString*) loadVideoFromCache: (NSString*) url
{
    NSArray* arr = [url componentsSeparatedByString:@"/"];
    NSString* name = arr[arr.count - 1];
    NSString* filePath = [[NSString alloc]initWithFormat:@"%@/%@", self.cacheDir, name];
    BOOL ret = [self.fileManager fileExistsAtPath:filePath];
    if(!ret){
        return nil;
    }
    else{
        return filePath;
    }
}

-(UIImage*) getRawImg: (NSURL*) url
{
    AVURLAsset* asset = [[AVURLAsset alloc]initWithURL:url options:nil];
    AVAssetImageGenerator* assetGen = [[AVAssetImageGenerator alloc]initWithAsset:asset];
    
    assetGen.appliesPreferredTrackTransform = YES;
    CMTime time = CMTimeMakeWithSeconds(0.0, 600);
    NSError *error = nil;
    CMTime actualTime;
    CGImageRef image = [assetGen copyCGImageAtTime:time actualTime:&actualTime error:&error];
    UIImage *videoImage = [[UIImage alloc] initWithCGImage:image];
    CGImageRelease(image);
    return videoImage;
}

-(void)deleteCache
{
    NSArray* contents = [self.fileManager contentsOfDirectoryAtPath:self.cacheDir error:nil];
    NSDate* date = [NSDate date];
    NSTimeInterval curTimeInterval = 3 * 24 * 60 * 60;
    for(int i = 0; i < contents.count; i++){
        NSString* str = contents[i];
        str = [NSString stringWithFormat:@"/%@",str];
        NSString* filePath = [self.cacheDir stringByAppendingString:str];
        NSDictionary* fileAttributes = [self.fileManager attributesOfItemAtPath:filePath error:nil];
        NSDate* fileModeDate = [fileAttributes objectForKey:NSFileModificationDate];
        NSTimeInterval timeInterval = [date timeIntervalSinceDate:fileModeDate];
        if(timeInterval > curTimeInterval){
            NSLog(@"[Info] Delete the cache file at path: %@", filePath);
            [self.fileManager removeItemAtPath:filePath error:nil];
        }
    }
}

-(NSString*)moveMediaToCache:(NSString*)filePath
{
    NSArray* arr = [filePath componentsSeparatedByString:@"/"];
    NSString* name = arr[arr.count - 1];
    NSString* newFilePath = [[NSString alloc]initWithFormat:@"%@/%@", self.cacheDir, name];
    BOOL ret = [self.fileManager moveItemAtPath:filePath toPath:newFilePath error:nil];
    if(ret){
        return newFilePath;
    }
    else{
        return nil;
    }
}

@end
